(function () {
/*z._calendar_tpl = {
        'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
        'yearscroll': true, // show year scroller
        'weekstart': 0, // first day of week: 0-Su or 1-Mo
        'centyear'  : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
        'imgpath' : 'img/' // directory with calendar images
    };*/
z._calendar_tpl = {
        'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
        'yearscroll': true, // show year scroller
        'weekstart': 0, // first day of week: 0-Su or 1-Mo
        'centyear'  : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
        'imgpath' : 'http://cdn.i.com/img/icon/' // directory with calendar images
    };
    
z.Calendar = function (dt) {
    this.browzer = z.browzer();
    if ( ! z.Calendars) {
        z.Calendars = [];
    }
    this.id = z.Calendars.length;
    z.Calendars[this.id] = this;
    this.today = new Date();
    //this.today.setSeconds(0);
    this._setTime(dt);
    this.tpl = z._calendar_tpl;
};
    
/*    
z.Calendar = function (input, tpl) {
    if (tpl) {
        this.tpl = tpl;
    } else {
        this.tpl = z._calendar_tpl;
    }
    if ( ! input || input.tagName != 'INPUT') {
        return alert ('input cannot be none');
    }
    this.input = input;
    this.browzer = z.browzer();
    
    if ( ! z.Calendars) {
        z.Calendars = [];
    }
    this.id = z.Calendars.length;
    z.Calendars[this.id] = this;
    
    var othis = this;
    this.input.onclick = function () {
        othis.show();
    }
}
*/

z.Calendar.prototype = {
    goToday: function () {
        this.today = new Date();
        this.selectedDay = new Date(this.today.getTime());
        this.update();
    },
    toString: function () {
        var t = this.selectedDay;
        return t.getFullYear() + '-' + (t.getMonth() + 1) + '-' + t.getDate() + ' ' + t.getHours() + ':' + t.getMinutes() + ':' + t.getSeconds();
    },
    _setTime: function (dt) {
        if (dt) {
            if (typeof(dt) == 'number') {
                this.selectedDay = new Date(dt);
            } else if (typeof(dt) == 'string') {
                this.selectedDay = new Date(this.parse(dt));
            } else {
                return alert('date format error');
            }
        } else {
            this.selectedDay = new Date(this.today.getTime());
        }
    },
    setTime: function (dt) {
        this._setTime(dt);
        this.update();
    },
    setFullYear: function (year) {
        this.selectedDay.setFullYear(year);
        this.update();
    },
    preYear: function () {
        this.setFullYear(this.selectedDay.getFullYear() - 1);
    },
    nextYear: function () {
        this.setFullYear(this.selectedDay.getFullYear() + 1);
    },
    preMonth: function () {
        this.setMonth(this.selectedDay.getMonth());
    },
    nextMonth: function () {
        this.setMonth(this.selectedDay.getMonth() + 2);
    },
    setMonth: function (month) {
        // if (month < 1 || month > 12) {
            // return alert ("Invalid month value: '" + month + "'.\nAllowed range is 01-12.");
        // } else {
            //this.selectedDay.setMonth(month - 1);
            this._setMonth(month);
            this.update();
        // }
    },
    _setMonth: function(month) {
        this.selectedDay.setMonth(month - 1);
    },
    setDate: function (date) {
        var d = this.selectedDay;
        var month = d.getMonth();
        var numdays = (new Date(d.getFullYear(), month, 0)).getDate();
        alert(month);
        if (date > numdays) {
            return alert("Invalid day of month value: '" + date + "'.\nAllowed range for selected month " + month + " is 01 - " + numdays + ".");
        }
        this.selectedDay.setDate(date);
        this.update();
    },
    setHours: function (hours) {
        if (hours < 0 || hours > 23) {
            return alert('hours error');
        }
        this.selectedDay.setHours(hours);
        //this.update();
    },
    setHoursFromInput: function (input) {
        var v = parseInt(input.value);
        if (isNaN(v)) v = 0;
        if (v > 23) v = 23;
        if (v < 0) v = 0;
        input.value = v;
        this.setHours(v);
        //input.focus();
        //input.focus();
    },
    setMinutes: function (minutes) {
        if (minutes < 0 || minutes > 59) {
            return alert('minutes error');
        }
        this.selectedDay.setMinutes(minutes);
        //this.update();
    },
    setMinutesFromInput: function (input) {
        var v = parseInt(input.value);
        if (isNaN(v) || v < 0) {
            v = 0;
            input.value = v;
        }
        if (v > 59) {
            v = 59;
            input.value = v;
        }
        
        this.setMinutes(v);
    },
    setSeconds: function (seconds) {
        if (seconds < 0 || seconds > 59) {
            return alert('seconds error');
        }
        this.selectedDay.setSeconds(seconds);
    },
    setSecondsFromInput: function (input) {
        var v = parseInt(input.value);
        if (isNaN(v) || v < 0) {
            v = 0;
            input.value = v;
        } else if (v > 59) {
            v = 59;
            input.value = v;
        }
        this.setSeconds(v);
    },
    parse: function (strDate) {
        var reDate = /^\s*(\d{4})\-(\d{1,2})\-(\d{1,2})\s*(\d{1,2})\:(\d{1,2})\:(\d{1,2})\s*$/;
        var RegExq = reDate.exec(strDate);
        if (!RegExq) {
            return alert('Invalid date: "' + strDate + '".\nAccected format is yyyy-mm-dd hh:mm:ss');
        }
        var year = Number(RegExq[1]),
            month = Number(RegExq[2]),
            day = Number(RegExq[3]),
            hour = Number(RegExq[4]),
            minutes = Number(RegExq[5]),
            seconds = Number(RegExq[6]);
        if (month < 1 || month > 12) {
            return alert ("Invalid month value: '" + month + "'.\nAllowed range is 01-12.");
        }
        
        var numdays = new Date(year, month, 0);
        
        if (day > numdays.getDate()) {
            return alert("Invalid day of month value: '" + day + "'.\nAllowed range for selected month is 01 - " + numdays.getDate() + ".");
        }
        if (hour < 0 || hour > 23) {
            return alert('hour error');
        }
        if (minutes < 0 || minutes > 59) {
            return alert('minutes error');
        }
        if (seconds < 0 || seconds > 59) {
            return alert('seconds error');
        }
        month --;
        //alert(month + ' ' + day);
        return new Date(year, month, day, hour, minutes, seconds);
    }, 
    setPos: function (x, y) {
        this.x = x;
        this.y = y;
    },
    show: function (dt) {
        if ( ! this.div) {
            var div = document.createElement('div');
            div.className = 'calendar';
            div.style.position = 'absolute';
            div.style.width = "200px";
            div.style.height = "166px";
            div.width = 200;
            div.height = 166;
            var othis = this;
            div.onmouseout = function (e) {
                othis.autoHide(e);
            };
            this.div = div;
            document.body.appendChild(this.div);
        }
        if (! this.iframe && this.browzer.browzer == 'msie' && parseInt(this.browzer.version) < 7) {
            var iframe = document.createElement('iframe');
            iframe.style.filter = 'alpha(opacity=0)';
            iframe.src = this.tpl.imgpath + 'pixel.gif';
            document.body.appendChild(iframe);
            this.iframe = iframe;
        }
        this.div.style.left = this.x + 'px';
        this.div.style.top = this.y + 'px';
        this.hide();
        this._setTime(dt);
        if ( ! this.update()) {
            return;
        }
        
        this.div.style.display = 'block';
        if (this.iframe) this.iframe.style.display = 'block';
        this.visible = true;
    },
    isSameDay: function (d1, d2) {
        if (d1.getDate() != d2.getDate()) {
            return false;
        }
        if (d1.getMonth() != d2.getMonth()) {
            return false;
        }
        if (d1.getFullYear() != d2.getFullYear()) {
            return false;
        }
        return true;
    },
    hide: function () {
        if ( ! this.visible) {
            return;
        }
        
        if (this.iframe) {
            this.iframe.style.display = 'none';
        }
        this.div.style.display = 'none';
        this.visible = false;
    },
    autoHide: function (e) {
        e = e || event;
        if (e !== undefined && this.div) {
            var div = this.div;
            var pos = z.getMousePos(e);
            var x = pos.x - this.x;
            var y = pos.y - this.y;
            
            if (x > div.width || x < 0 || y > div.height || y <0) {
                this._mouseout = true;
            } else {
                this._mouseout = false;
            }
        }
        if (true === this._mouseout) {
            this.hide();
        }
    },
    update: function () {
        if ( ! this.today) {
            this.today = new Date();
        }
        if ( ! this.selectedDay) {
            this.selectedDay = new Date(this.today.getTime());
        }
        
        var date = new Date(this.selectedDay);
        
        // first day to display
        var firstDay = new Date(date); // check
        firstDay.setDate(1);
        firstDay.setDate(1 - (7 + firstDay.getDay() - this.tpl.weekstart) % 7);
        
        var html = '<table class="header"><tbody><tr><td onclick="z.Calendars[' + this.id + '].preYear()"><img src="' + this.tpl.imgpath + 'prev_year.gif" /></td><td onclick="z.Calendars[' + this.id + '].preMonth()"><img src="' + this.tpl.imgpath + 'prev_mon.gif" /></td><td align="center">'+ this.tpl.months[date.getMonth()] + ' ' + date.getFullYear() + '</td><td onclick="z.Calendars[' + this.id + '].nextMonth()"><img src="' + this.tpl.imgpath + 'next_mon.gif" /></td><td onclick="z.Calendars[' + this.id + '].nextYear()"><img src="' + this.tpl.imgpath + 'next_year.gif" /></td></tr></tbody></table>';
        
        html += '<table class="body"><tbody><tr class="wd">'
        for (var i=0; i < 7; i++) {
            var weekDay = (this.tpl.weekstart + i) % 7;
            var css = '';
            if (weekDay == 0 || weekDay == 6) {
                css = ' class="weekend"';
            }
            html += '<th' + css + '>' + this.tpl.weekdays[weekDay] + '</th>';
        }
        html += '</tr>';
        
        var currentDay = new Date(firstDay);
        var dateMon = date.getMonth();
        var firstDayMon = firstDay.getMonth();
        
        var nDate;
        var currentMon = currentDay.getMonth();
        while (currentMon == dateMon || currentMon == firstDayMon) {
            html += '<tr>';
            for (var wd = 0; wd < 7; wd++) {
                nDate = currentDay.getDate();
                currentMon = currentDay.getMonth();
                var css = [];
                if (currentMon != dateMon) {
                    css[css.length] = 'othermonth';
                }
                if (currentDay.getDay() ==0 || currentDay.getDay() == 6) {
                    css[css.length] = 'weekend';
                }
                //var dayMs = 24 * 60 * 60 * 1000;
                if (this.isSameDay(currentDay, this.today)) {
                    //alert('today');
                    css[css.length] = 'today';
                }
                if (this.isSameDay(currentDay, this.selectedDay)) {
                    //alert('select-day');
                    css[css.length] = 'selected-day';
                }
                //html += '<td onclick="' + ((currentMon != dateMon) ? 'z.Calendars[' + this.id + ']._setMonth(' + (currentMon + 1) + ');' : '') + 'z.Calendars[' + this.id + '].setDate(' + nDate + ')">' + nDate + '</td>';
                html += '<td ' + ((css.length>0) ? ('class="' + css.join(' ') + '"') : '') +' onclick="z.Calendars[' + this.id + '].setTime(' + currentDay.getTime() + ')"><div>' + nDate + '</div></td>';
                currentDay.setDate(++nDate);
            }
            html += '</tr>';
        }
        
        html += '</tbody></table>';
        html += '<table class="footer"><tbody><tr>';
        html += '<td><a href="javascript:z.Calendars[' + this.id + '].goToday()">Now</a></td>';
        html += '<td><input onchange="z.Calendars[' + this.id + '].setHoursFromInput(this);" type="text" value="' + this.selectedDay.getHours() +'" /> : ';
        html += '<input onchange="z.Calendars[' + this.id + '].setMinutesFromInput(this);" type="text" value="' + this.selectedDay.getMinutes() +'" /> :';
        html += '<input onchange="z.Calendars[' + this.id + '].setSecondsFromInput(this);" type="text" value="' + this.selectedDay.getSeconds() +'" /></td>';
        html += '<td><a href="javascript:z.Calendars[' + this.id + '].submit();">ok</a></td><td><a href="javascript:z.Calendars[' + this.id + '].hide();">X</a></td>';
        html += '</tr></tbody></table>';
        
        //alert (html);
        this.div.innerHTML = html;
        return true;
    },
    submit: function () {
        alert(this.selectedDay);
    }
}
})();